﻿#include <opencv2/opencv.hpp>;
using namespace cv;


//Robert算子函数搭建
Mat robert(Mat srcImage)
{
	Mat dstImage = srcImage.clone();
	int nRows = dstImage.rows;
	int nCols = dstImage.cols;
	for (int i = 0; i < nRows - 1; i++) 
	{
		for (int j = 0; j < nCols - 1; j++) {
			//根据公式计算
			int t1 = (srcImage.at<uchar>(i, j) -
				srcImage.at<uchar>(i + 1, j + 1))*
				(srcImage.at<uchar>(i, j) -
					srcImage.at<uchar>(i + 1, j + 1));
			int t2 = (srcImage.at<uchar>(i + 1, j) -
				srcImage.at<uchar>(i, j + 1))*
				(srcImage.at<uchar>(i + 1, j) -
					srcImage.at<uchar>(i, j + 1));
			//计算g（x,y）
			dstImage.at<uchar>(i, j) = (uchar)sqrt(t1 + t2);
		}
	}
	return dstImage;
}

int main(void)
{
	//读取原始图片，显示原始图片及对应的灰度图
	const char *fig = ("G:\\Engineering software\\OpenCV4.0.1\\opencv-4.0.1\\samples\\data\\lena.jpg");
	Mat image = imread(fig);
	if (image.empty())
	{
		printf("Picture loading failed !\n");
		system("pause");
		return -1;
	}
	Mat gray, Robert, sobel_image, Laplace, LoG, canny, Log;
	imshow("原始图片", image);
	cvtColor(image, gray, COLOR_BGR2GRAY);
	imshow("灰度图片", gray);
	waitKey();

	//对原始图片进行各类算子边缘检测，比存储到相应的变量中，同时显示输出
	Robert = robert(gray);
	imshow("Robert变换", Robert);
	waitKey();

	/*
	In all cases except one, the ksize×ksize separable kernel is used to calculate the derivative. When ksize = 1, the 3×1 or 1×3 kernel is used (that is, no Gaussian smoothing is done). ksize = 1 can only be used for the first or the second x- or y- derivatives.
	The Sobel operators combine Gaussian smoothing and differentiation, so the result is more or less resistant to the noise.
	The function is called with ( xorder = 1, yorder = 0, ksize = 3) or ( xorder = 0, yorder = 1, ksize = 3) to calculate the first x- or y- image derivative. 
		The first case corresponds to a kernel of:
			[-1 0 1; -2 0 2; -1 0 1]
		The second case corresponds to a kernel of:
			[-1 -2 -1; 0 0 0; 1 2 1]

	void cv::Sobel(	InputArray	src,					
					OutputArray dst,
					int ddepth,							//output image depth. In the case of 8-bit input images, it will result in truncated derivatives.
					int dx,								//order of the derivative x.
					int dy,								//order of the derivative y.
					int ksize = 3,						//size of the extended Sobel kernel; it must be 1, 3, 5, or 7.如果是3×3的kernel， 使用改进版Scharr函数的结果要比Sobel算子函数的结果要精确。
					double scale = 1,					//optional scale factor for the computed derivative values; by default, no scaling is applied.
					double delta = 0,					//optional delta value that is added to the results prior to storing them in dst.
					int borderType = BORDER_DEFAULT 
	)		
	*/
	Sobel(gray, sobel_image, CV_16S, 1, 1, 3, 1, 0, BORDER_DEFAULT);
	convertScaleAbs(sobel_image, sobel_image, 1, 0);	//On each element of the input array, the function convertScaleAbs performs three operations sequentially: scaling, taking an absolute value, conversion to an unsigned 8-bit type: dst(I)=saturate\_cast<uchar>(|src(I)∗alpha+beta|).
	imshow("Sobel变换", sobel_image);
	waitKey();

	/*
	void cv::Laplacian(	InputArray  src,						
						OutputArray dst,
						int ddepth,							
						int ksize = 1,						//Aperture size used to compute the second-derivative filters.When ksize == 1, the Laplacian is computed by filtering the image with the following 3×3 aperture:[0 1 0; 1 -4 1; 0 1 0].
						double scale = 1,
						double delta = 0,
						int borderType = BORDER_DEFAULT 
	)	
	*/
	Laplacian(gray, Laplace, CV_16S, 3, 1, 0, BORDER_DEFAULT);	//ksize == 3，对应的kernel应该为[2 0 2; 0 -8 0; 2 0 2];
	convertScaleAbs(Laplace, Laplace,1, 0);						
	imshow("Laplace变换", Laplace);
	waitKey();

	/*
	void cv::Canny( InputArray 	image,
					OutputArray edges,
					double threshold1，			//first threshold for the hysteresis procedure.小于threshold1值的像素认定为假边缘，去除（设为255白色）。
					double threshold2,			//second threshold for the hysteresis procedure.大于threshold2值得像素认定为强边缘点（真边缘），全部保留（设为0黑色）。介于两者之间的标记为弱边缘点，需判断邻接像素中是否有大于threshold2值的。
					int apertureSize = 3,		//aperture size for the Sobel operator.默认3*3邻域。
					bool L2gradient = false 
	)	
	*/
	Canny(gray, canny, 50, 200, 3, false);
	imshow("Canny变换", canny);
	waitKey();

	//LoG算子即先对图像做一次高斯滤波，再用一次Laplace算子。
	GaussianBlur(image, image, Size(3, 3), 0, 0,BORDER_DEFAULT);
	cvtColor(image, gray, COLOR_BGR2GRAY);
	Laplacian(gray, Log, CV_16S, 3);
	convertScaleAbs(Log, Log);
	imshow("Log变换", Log);
	waitKey();

}